// ==UserScript==
// @name         看动态排行榜
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://www.sif.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=sif.com
// @updateURL    https://gitee.com/great-pacey/tampermonkey/raw/master/sifTimeMachine.user.js
// @grant        GM_registerMenuCommand
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// ==/UserScript==


(function () {
    let END_DAY_LIST = []
    let ConsecutiveTimes = 0
    let granularity, ASIN
    const LONG_DURATION = 1000 * 30
    const SHORT_DURATION = 1000 * 2
    const KEYWORD_TYPE = { ALL: 'all', ZR: 'nf', AD: 'sp' }
    let keywordType = KEYWORD_TYPE.ALL

    function getGranularity() {
        if (granularity) return granularity
        let text = document.querySelectorAll('.search input.el-input__inner')[1].value
        if (text.includes('周')) {
            granularity = 'week'
        } else if (text.includes('月')) {
            granularity = 'month'
        } else if (text.includes('天')) {
            granularity = 'day'
        }
        return granularity
    }

    function getASIN() {
        if (ASIN) return ASIN
        ASIN = document.querySelectorAll('input')[2].value
        return ASIN
    }

    async function preWait() {
        if (shouldWait()) {
            await wait(LONG_DURATION)
            ConsecutiveTimes = 0
        } else {
            await wait(SHORT_DURATION)
        }
    }

    async function getDataByDay(day) {
        let result = [], pageNum = 1

        let txt = await getOnePageData(day, pageNum)
        let resData = JSON.parse(txt).data
        let total = resData.total

        let data = format(resData)
        result = result.concat(data)
        while (result.length < total) {
            pageNum++
            let txt = await getOnePageData(day, pageNum)
            let resData = JSON.parse(txt).data
            let data = format(resData)
            result = result.concat(data)
        }
        return result
    }

    async function getOnePageData(day, pageNum) {
        await preWait()
        let txt = await getData(day, pageNum)
        while (txt.includes('访问过于频繁，请稍后重试')) {
            await wait(LONG_DURATION)
            ConsecutiveTimes = 0
            txt = await getData(day, pageNum)
        }
        return txt
    }

    async function getData(day, pageNum = 1) {
        return new Promise(resolve => {
            const t = Date.now()
            const data = {
                "granularity": getGranularity(),
                "type": "all",
                "keywordType": keywordType,
                "asin": getASIN(),
                "searchKeyword": "",
                "endDay": day,
                "sortBy": "diffScore",
                "filter": null,
                "desc": true,
                "pageNum": pageNum,
                "pageSize": 100
            }
            const authorization = unsafeWindow.localStorage.token

            GM_xmlhttpRequest({
                method: "POST",
                url: `https://www.sif.com/api/search/exposureScore/detail?country=US&_t=${t}`,
                headers: {
                    authorization,
                    Accept: 'application/json, text/plain, */*',
                    Origin: `https://www.sif.com`,
                    'Referer': `https://www.sif.com/track?country=US`,
                    'Content-Type': 'application/json;charset=UTF-8',
                    'Sec-Fetch-Site': `same-origin`
                },
                data: JSON.stringify(data),
                onload: function (p) {
                    const token = p.responseHeaders.match(/authorization\:\s(.+)\r\nconnection/)[1]
                    unsafeWindow.localStorage.token = token
                    ConsecutiveTimes++
                    resolve(p.responseText)
                }
            })
        })
    }

    function format(data) {
        const date = data.extraData.date
        const details = data.details.map(i => {
            return {
                keyword: i.keyword,
                value: i.score,
                date
            }
        })
        return details
    }

    async function nextPage() {
        return new Promise(async resolve => {
            const btn = document.querySelector('.btn-next')
            if (hasNextPage()) {
                btn.click()
                let hasUpdated = updateEndDayList()
                while (!hasUpdated) {
                    await wait()
                    hasUpdated = updateEndDayList()
                }
            }
            resolve(hasNextPage())
        })
    }

    function updateEndDayList() {
        let arr = [].slice.call(document.querySelectorAll('tbody td:first-child')).map(i => i.innerText.trim())
        newList = Array.from(new Set(END_DAY_LIST.concat(arr)))
        const hasUpdated = newList.length > END_DAY_LIST.length
        END_DAY_LIST = newList
        return hasUpdated
    }

    function hasNextPage() {
        const btn = document.querySelector('.btn-next')
        const hasNextPage = !btn.disabled
        return hasNextPage
    }

    async function getAllEndDayList() {
        updateEndDayList()
        let hasNPage = hasNextPage()
        while (hasNPage) {
            hasNPage = await nextPage()
        }
    }

    async function wait(num = 1000) {
        return new Promise(resolve => {
            setTimeout(resolve, num)
        })
    }

    async function getDataInbulk() {
        let result = []
        while (END_DAY_LIST.length) {
            let endDay = END_DAY_LIST.pop()
            let data = await getDataByDay(endDay)
            result.push(data)
            console.log(endDay, 'successed')
        }
        return result
    }

    function shouldWait() {
        return ConsecutiveTimes >= 13
    }

    async function main() {
        await getAllEndDayList()
        const data = await getDataInbulk()
        goNewPage(data)
    }

    GM_registerMenuCommand('全部', main)

    GM_registerMenuCommand('广告', () => {
        keywordType = KEYWORD_TYPE.AD
        main()
    })

    GM_registerMenuCommand('自然', () => {
        keywordType = KEYWORD_TYPE.AD
        main()
    })

})()

function goNewPage(data) {
    let newWin = window.open();
    newWin.DATA = data
    const html = genHTML()
    setHTMLWithScript(newWin, html);
}

function setHTMLWithScript(win, rawHTML) {
    const container = win.document.documentElement;
    container.innerHTML = rawHTML;
    const scripts = container.querySelectorAll('script');

    return Array.prototype.slice.apply(scripts).reduce((chain, script) => {
        return chain.then(() => runScript(script, win));
    }, Promise.resolve());
}

function runScript(script, win) {
    return new Promise((reslove, rejected) => {
        const newScript = win.document.createElement('script');
        newScript.innerHTML = script.innerHTML;
        const src = script.getAttribute('src');
        if (src) newScript.setAttribute('src', src);

        newScript.onload = () => reslove();
        newScript.onerror = err => rejected();
        win.document.head.appendChild(newScript);
        win.document.head.removeChild(newScript);
        if (!src) {
            reslove();
        }
    })
}

function genHTML() {
    let html = `<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>动态排行榜</title>
        <style>
            #main {
                height: 500px;
                width: 100%;
            }
        </style>
    </head>
    <body>
        <button id="start">开始</button>
        <div id="main"></div>
        <script src="https://cdn.jsdelivr.net/npm/echarts@5.3.3/dist/echarts.min.js"></script>
        <script>
        const DURATION = 2000
        let count = 0;
        const KEYWORDS = DATA.map(i => i.map(n => n.keyword)).reduce((p, n) => Array.from(new Set(p.concat(n))))
        
        function isStop() {
          return count === DATA.length
        }
        
        function genData() {
          let data, date
          if (DATA[count]) {
            data = KEYWORDS.map(k => {
              var a = DATA[count].filter(i => i.keyword === k)
              if (a.length) {
                return a[0]
              } else {
                return {value: 0, keyword: k}
              }
            })
            date = data[0].date
            value = data.map(i => parseInt(i.value))
            count++
          } else {
            return false
          }
        
          return { value, date }
        }
        
        function main() {
          var myChart = echarts.init(document.getElementById('main'));
          // var mm = genData()
          // var data = mm.value
        
          let option = {
            grid: {
              left: "30%"
            },
            xAxis: {
              max: 'dataMax'
            },
            yAxis: {
              type: 'category',
              // data: mm.keyword,
              inverse: true,
              animationDuration: 300,
              animationDurationUpdate: 300,
              max: 9
            },
            series: [
              {
                realtimeSort: true,
                name: 'X',
                type: 'bar',
                // data: data,
                label: {
                  show: true,
                  position: 'right',
                  valueAnimation: true
                }
              }
            ],
            legend: { show: true },
            animationDuration: 1.5 * DURATION,
            animationDurationUpdate: 1.5 * DURATION,
            animationEasing: 'linear',
            animationEasingUpdate: 'linear'
          };
        
          function update() {
            var m = genData()
            option.series[0].data = m.value
            option.series[0].name = m.date
            option.yAxis.data = KEYWORDS
            myChart.setOption(option);
          }
            var start = document.getElementById("start")
            start.onclick = function() {
                count = 0
                update()
                var ttt = setInterval(() => {
                    if (!isStop()) {
                        update()
                    } else {
                        clearInterval(ttt)
                    }
                }, DURATION);
            }
        }
        setTimeout(main, 0)
        </script>
    </body>
    </html>`
    return html
}